// QSFLAME.H - "cosmic recursive fractal flames"
// GNU version by Scott Draves <http://scottdraves.com> Copyright (C) 1992
// W95 version by Michael Sargent <msargent@zoo.uvm.edu> Copyright (C) 1999
// Revisions by Michael Sargent <msargent@uvm.edu> Copyright (C) 2018
/*=========================================================================
   This is unsupported, non-standard software. It is provided "as is" and
   any express or implied warranties, including, but not limited to, the
   implied warranties of merchantability and fitness for a particular
   purpose are disclaimed. In no event shall the author be liable for any
   direct, indirect, incidental, special, exemplary, or consequential
   damages (including, but not limited to, procurement of substitute goods
   or services; loss of use, data or profits; or business interruption)
   however caused and on any theory of liablility, whether in contract,
   strict liability, or tort (including negligence or otherwise) arising in
   any way out of the use of this software, even if advised of the
   possibility of such damage.
=========================================================================
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; If not, see <https://www.gnu.org/licenses/>.
//=======================================================================*/
// This is the header file for QSFLAME.C
// Contents: 1) constant #defines
//           2) macro #defines
//           3) C library #includes
//           4) struct/typedef definitions
//           5) function declarations
//           6) global variable declarations
//           7) message and resource #defines
//=========================================================================

////////  1) //////  constant #defines ////////////////////////////////////

#define EPS (1e-10)
#define NVARS   7
#define NXFORMS 6
#define CHOOSE_XFORM_GRAIN 100
#define PREFILTER_WHITE (1 << 10)
#define FUSE 50                             // initial discarded iterations
#define FILTER_CUTOFF 2.5                   // "clamp filter to 0 at this std
                                            //    dev (2.5 ~= 0.0125)" (S.D.)

////////  2) //////  macro #defines ///////////////////////////////////////

#define RGBADD(rgb1, rgb2)   {rgb1.r = rgb1.r + rgb2.r; \
                              rgb1.g = rgb1.g + rgb2.g; \
                              rgb1.b = rgb1.b + rgb2.b;}
#define RGBMULT(rgb, n)      {rgb.r = rgb.r * n; \
                              rgb.g = rgb.g * n; \
                              rgb.b = rgb.b * n;}
#define RGBCLAMP(rgb)        {if (rgb.r > 255.0) rgb.r = 255.0; \
                              if (rgb.g > 255.0) rgb.g = 255.0; \
                              if (rgb.b > 255.0) rgb.b = 255.0; \
                              if (rgb.r < 0.0) rgb.r = 0.0; \
                              if (rgb.g < 0.0) rgb.g = 0.0; \
                              if (rgb.b < 0.0) rgb.b = 0.0;}
#define vlen(x) (sizeof(x) / sizeof(*x))
#define random_distrib(v) ((v)[random(vlen(v))])
#define bump_no_overflow(dest, delta) { \
   int tt_ = dest + delta;              \
   if (tt_ > dest) dest = tt_;          \
}

////////  3) //////  C library #includes //////////////////////////////////

#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <dir.h>
#include <time.h>

////////  4) //////  struct/typedef definitions ///////////////////////////

typedef struct {
   double var[NVARS];   // normalized interp coefs between variations
   double c[3][2];      // the coefs to the affine part of the function
   double density;      // prob. that this function is chosen. 0 - 1
   double color;        // color coord. for this function. 0/1
} XFRM;                 // "XFRM" because WINGDI.H declares "XFORM"

typedef struct {
   int iter;                      // number of iterations; currently 100,000
   int active;                    // number of currently active xforms
   int radius;                    // radius of gaussian filter:  1 - 100 [4]
   int white_level;               // currently 255
   double gamma;                  // 0.1 - 10.0 [1.0 == no effect]
   int brightness;                // -100 - 100 [ 0 == no effect]
   double contrast;               // currently 1.0
   double center[2];              // camera center: [0.0, 0.0]
   double scale;                  // > 1.0 = zoom in; < 1.0 = zoom out [1.0]
   double pixels_per_unit;        // scale; currently 100
   double sample_density;         // samples per pixel; currently 5.0
} PRM;

typedef struct
{
   double r, g, b;
}  RGBPIXEL;

typedef struct
{
   double left, right, top, bottom;
} DRECT;

typedef struct {
   char id[15];                   // "QSFLAME_PARAMS"
   PRM prm;
   XFRM x[NXFORMS];
} PRMSAVE;

struct THUMB                      // for GIF and TARGA saving routines
{
   int mod, xth, yth, xright, ybottom;
};

////////  5) //////  function declarations ////////////////////////////////
//----- QSFlame.c -----
void setup_cmap(void);
void setup_filter(int radius);
void setup_gamma(double gamma);
void iterate(void);
void apply_filter(void);
void getRGBPIXEL(RGBPIXEL *rgb, int x, int y);
void random_xform(int ivar);
double qsrandom01(void);
double qsrandom11(void);
void initialize(void);
void initializemore(void);

//----- QSFGUI.c -----
WPARAM ProgramDriver(void);
int InitWindowClass(HANDLE hInstance);
int CreateMainWindow(HANDLE hInstance, int nCmdShow);
LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT message, WPARAM wParam,
									     LPARAM lParam);
LRESULT CALLBACK PopupWindowProc(HWND hPopupWnd, UINT message,
                                 WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ImageDialogProc(HWND hDwnd, UINT message,
                                 WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CoefDialogProc(HWND hDwnd, UINT message,
                                WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK IParDialogProc(HWND hDwnd, UINT message,
                                WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK ColorDialogProc(HWND hDwnd, UINT message,
                                 WPARAM wParam, LPARAM lParam);
int initgraphics(HWND hWnd);
void InitOpenFile(void);
int splash(HWND hwnd, int index);
int OpenMapFile(void);
int showpalette(void);
int writetga(HDC hdc);

////////  6) //////  global variable declarations /////////////////////////

//----- flame variables -----
PRM p, pt;
XFRM x[NXFORMS], xt[NXFORMS];
int oversample, xos, yos;
int cmap[256][4];
double itable[210];
unsigned char gtable[256];
unsigned char *fbuffer;
short *hits;
DRECT bounds;

//----- global handles, window names and error messages -----
HINSTANCE g_hInstance;
HWND g_hWnd, g_hStatuswnd;
HWND g_hEwnd[51];
HDC g_vhdc, g_vabouthdc, g_phdc;
HBITMAP g_hBitmap, g_hAboutbitmap, g_phBitmap;
HACCEL g_hAccel;
//char helppath[MAX_PATH];
char szWinName[] = {"QSWindow"};
char szPopupWinName[] = {"QSPopupWindow"};
char szSplashWinName[] = {"QSSplashWindow"};
char *errormessage[4] = {
"Couldn't register main window class.",
"Couldn't register popup window class.",
"Couldn't create main window.",
"Couldn't initialize graphics.\nMinimum 24-bit color required."
};
char *paramerror[7] = {
"Generic parameter error.",
"coefficient range: -1.0 to 1.0",
"Each active set needs a selected formula.",
"probability range: 0.0 to 1.0",
"scale range: 0.1 to 10.0",
"Center out of bounds.",
"gamma range: 0.1 to 10.0"};

//----- graphics variables -----
int rback = 0, gback = 0, bback = 0;
COLORREF back = 0;
int xscreen, yscreen; 
int xres = 600, yres = 600;
int linetable[6000];              // 3 * maximum yres
RECT ClientRes;                   // for actual size of client window
POINT restable[10] = {{160, 120},   {200, 150},       // the possible
                      {320, 200},   {320, 240},       // image dimensions
                      {480, 360},   {640, 480},
                      {800, 600},   {1024, 768},
                      {1280, 1024}, {1600, 1200}};

//----- flags -----
BOOL oksplash = FALSE;            // TRUE allows display of splash window
BOOL aboutflag = FALSE;           // TRUE if about box is selected
BOOL fbufferflag = FALSE;         // TRUE if image buffer allocated
BOOL okzoom = FALSE;              // these flags tell program what to do if
BOOL drawbox = FALSE;             //    mouse buttons are clicked for
BOOL zooming = FALSE;             //    drawing zoombox or new image
BOOL clrscr = TRUE;               // clears screen before rendering image
BOOL aspectflag = TRUE;           // preserves 4/3 aspect ratio for zoombox
BOOL okpalette = FALSE;           // used by gifsavew.inc
BOOL hitflag = FALSE;             // TRUE if hits buffer allocated
BOOL reitflag = FALSE;            // TRUE if re-iterating
BOOL infinite = FALSE;            // TRUE for infinite iteration looping

//----- scrolling variables -----
SCROLLINFO si;
int xCurrentScroll = 0;
int yCurrentScroll = 0;
int lastdisplayline;

//----- open/save file variables -----
char string[MAX_PATH];
PRMSAVE ps;

OPENFILENAME ofn;
char filter[] = {"Fractint .map files (*.map)\0*.map\0\0"};
char file[MAX_PATH];
char filetitle[MAX_PATH];
char title[] = {"Select a Fractint .MAP File"};
char defext[5] = {"map"};

OPENFILENAME oprmn;
char prmfilter[] = {"Parameter files (*.flm)\0*.flm\0\0"};
char prmfile[MAX_PATH];
char prmfiletitle[MAX_PATH];
char prmtitle[] = {"Select a parameter file:"};
char prmdefext[5] = {"flm"};

OPENFILENAME sprmn;
char sprmfilter[] = {"Parameter files (*.flm)\0*.flm\0\0"};
char sprmfile[MAX_PATH];
char sprmfiletitle[MAX_PATH];
char sprmtitle[] = {"Select a file for saving the current parameters:"};
char sprmdefext[5] = {"flm"};

OPENFILENAME stgan;
char tgafilter[] = {"Targa files (*.tga)\0*.tga\0\0"};
char tgafile[MAX_PATH];
char tgafiletitle[MAX_PATH];
char tgatitle[] = {"Select a file for saving your image:"};
char tgadefext[5] = {"tga"};

char *saveerror[3] = {
   "Error opening a save file.",
   "Not enough memory to buffer image lines.",
   "Error writing to save file."
};

//----- palettes -----
unsigned char palette[256][3];                   // program's working palette
unsigned char paltemp[256][3];                   // temporary from MAP file
unsigned char fpalette[256][3] =                 // startup palette "rie05"
{{73, 125, 84}, {77, 141, 83}, {89, 146, 83}, {104, 154, 94}, 
{109, 170, 103}, {146, 198, 113}, {162, 214, 132}, {182, 226, 160}, 
{198, 234, 160}, {206, 234, 169}, {218, 242, 178}, {222, 238, 169}, 
{218, 226, 150}, {222, 230, 141}, {218, 230, 131}, {210, 222, 131}, 
{206, 222, 122}, {190, 219, 113}, {203, 226, 122}, {206, 226, 103}, 
{218, 226, 94}, {211, 222, 94}, {198, 222, 75}, {170, 210, 94}, 
{170, 206, 103}, {150, 194, 113}, {137, 174, 113}, {121, 170, 103}, 
{129, 174, 113}, {129, 182, 113}, {146, 198, 132}, {162, 222, 160}, 
{182, 218, 169}, {210, 234, 197}, {230, 246, 206}, {230, 246, 216}, 
{230, 242, 207}, {222, 234, 197}, {214, 238, 188}, {214, 234, 169}, 
{214, 230, 150}, {210, 230, 131}, {198, 230, 122}, {186, 219, 122}, 
{170, 206, 122}, {154, 198, 113}, {137, 182, 85}, {125, 178, 75}, 
{121, 170, 84}, {137, 153, 94}, {141, 174, 94}, {162, 182, 113}, 
{193, 201, 141}, {205, 205, 178}, {222, 230, 197}, {234, 250, 206}, 
{246, 254, 197}, {254, 241, 169}, {246, 234, 159}, {242, 250, 112}, 
{230, 238, 94}, {222, 234, 112}, {198, 222, 113}, {190, 219, 103}, 
{198, 206, 103}, {186, 214, 103}, {174, 214, 113}, {166, 218, 113}, 
{182, 214, 113}, {186, 219, 122}, {198, 226, 132}, {202, 226, 150},
{222, 222, 160}, {238, 234, 159}, {246, 233, 169}, {226, 238, 178}, 
{210, 234, 169}, {198, 234, 160}, {198, 230, 150}, {202, 226, 132}, 
{207, 230, 122}, {198, 226, 122}, {186, 222, 113}, {178, 214, 103},
{166, 206, 103}, {166, 202, 94}, {150, 190, 84}, {141, 186, 75}, 
{153, 174, 66}, {165, 169, 66}, {150, 182, 85}, {158, 194, 94}, 
{162, 194, 103}, {162, 206, 103}, {158, 206, 103}, {166, 210, 113}, 
{162, 202, 113}, {162, 210, 122}, {166, 214, 113}, {158, 206, 94}, 
{142, 194, 85}, {129, 174, 85}, {121, 166, 75}, {121, 174, 75}, 
{121, 157, 75}, {129, 162, 75}, {154, 148, 37}, {137, 157, 75}, 
{109, 154, 75}, {121, 162, 103}, {137, 170, 132}, {166, 198, 151}, 
{178, 218, 169}, {182, 214, 179}, {185, 210, 179}, {178, 218, 169},
{154, 198, 141}, {125, 178, 122}, {125, 186, 113}, {146, 194, 103}, 
{150, 194, 103}, {150, 194, 103}, {154, 194, 94}, {146, 198, 85}, 
{142, 194, 85}, {142, 182, 85}, {141, 182, 84}, {146, 194, 75}, 
{150, 194, 75}, {154, 198, 75}, {158, 194, 56}, {170, 198, 56}, 
{162, 206, 66}, {190, 210, 75}, {230, 187, 28}, {254, 198, 9}, 
{242, 208, 37}, {242, 225, 75}, {246, 237, 112}, {222, 242, 159}, 
{226, 238, 178}, {242, 242, 207}, {246, 242, 216}, {246, 246, 225}, 
{242, 242, 225}, {242, 241, 216}, {226, 242, 188}, {206, 234, 179},
{194, 226, 150}, {178, 214, 132}, {162, 210, 122}, {129, 194, 103}, 
{117, 166, 85}, {109, 149, 65}, {101, 153, 75}, {89, 150, 74}, 
{97, 158, 75}, {101, 162, 84}, {113, 170, 85}, {137, 194, 94}, 
{154, 206, 103}, {170, 206, 94}, {189, 193, 84}, {238, 208, 65}, 
{254, 228, 84}, {254, 233, 102}, {254, 221, 93}, {230, 205, 94}, 
{182, 206, 113}, {153, 177, 122}, {113, 154, 94}, {100, 150, 94}, 
{84, 129, 93}, {73, 121, 75}, {65, 117, 65}, {61, 113, 56}, 
{60, 109, 56}, {65, 113, 47}, {61, 109, 56}, {65, 109, 56}, 
{65, 113, 56}, {69, 117, 65}, {77, 129, 65}, {93, 141, 65}, 
{93, 150, 74}, {113, 158, 85}, {133, 170, 85}, {146, 190, 103}, 
{150, 190, 122}, {157, 190, 132}, {158, 202, 132}, {162, 210, 132}, 
{174, 219, 122}, {186, 222, 122}, {198, 230, 150}, {206, 230, 169}, 
{214, 230, 179}, {222, 234, 197}, {230, 246, 216}, {238, 237, 225}, 
{238, 234, 235}, {238, 238, 216}, {226, 238, 188}, {214, 230, 160}, 
{194, 218, 141}, {190, 198, 131}, {174, 198, 122}, {174, 202, 122}, 
{174, 214, 122}, {182, 219, 122}, {194, 214, 132}, {198, 226, 160}, 
{202, 226, 160}, {202, 226, 160}, {190, 222, 179}, {190, 222, 179}, 
{194, 230, 179}, {202, 230, 178}, {214, 234, 178}, {222, 230, 179}, 
{218, 234, 178}, {210, 230, 169}, {206, 218, 169}, {182, 222, 160},
{154, 194, 141}, {129, 170, 113}, {101, 154, 93}, {81, 141, 83}, 
{81, 133, 83}, {77, 125, 74}, {73, 121, 74}, {69, 129, 65},
{73, 121, 74}, {77, 129, 74}, {109, 133, 75}, {97, 146, 75}, 
{108, 154, 94}, {125, 178, 103}, {150, 202, 113}, {166, 210, 122}, 
{186, 222, 141}, {194, 222, 151}, {194, 218, 151}, {182, 218, 151}, 
{162, 218, 131}, {170, 214, 122}, {174, 210, 122}, {182, 210, 122}, 
{186, 214, 122}, {190, 214, 122}, {194, 218, 132}, {198, 230, 141}, 
{202, 230, 150}, {207, 230, 141}, {202, 218, 131}, {190, 206, 122}
};

////////  7) //////  message and resource #defines ////////////////////////
//----- custom messages -----
#define WM_PARAMERROR      (WM_USER + 1)

//----- resource #defines -----
//----- menu -----
#define IDM_LOADPRM  100
#define IDM_LOADPAL 110
#define IDM_SAVEPRM 120
#define IDM_SAVEIMAGE 130
#define IDM_EXIT  140
#define IDM_IMAGE  200
#define IDM_IMAGEPRM 210
#define IDM_COEF 220
#define IDM_COLORPRM 230
#define IDM_NEWRAND 240
#define IDM_NEWIMAGE 300
#define IDM_REITERATE 310
#define IDM_INFINITE 320
#define IDM_UNZOOM 330
#define IDM_APPLY 340
#define IDM_BRIGHT 350
#define IDM_GAMMA 360
#define IDM_HELP  400
#define IDM_ABOUT 410
#define IDM_GNU 420

//----- image dimensions -----
#define IDD_DLG_IMAGE  500
#define IDC_IDC_IEDIT1 510
#define IDC_IDC_IEDIT2 520

//----- palette selection -----
#define IDD_DLG_SHOWPAL 600
#define IDC_GO 610
#define IDC_TRY 620
#define IDC_FORGET 630

//----- coefficient selection -----
#define IDD_CDLG	   700
#define IDC_CGB1	   710
#define IDC_CGB2	   711
#define IDC_CGB3	   712
#define IDC_CGB4	   713
#define IDC_CGB5	   714
#define IDC_CGB6	   715
#define IDC_CEDIT000	720
#define IDC_CEDIT001	721
#define IDC_CEDIT010	722
#define IDC_CEDIT011	723
#define IDC_CEDIT020	724
#define IDC_CEDIT021	725
#define IDC_CEDIT100	726
#define IDC_CEDIT101	727
#define IDC_CEDIT110	728
#define IDC_CEDIT111	729
#define IDC_CEDIT120	730
#define IDC_CEDIT121	731
#define IDC_CEDIT200	732
#define IDC_CEDIT201	733
#define IDC_CEDIT210	734
#define IDC_CEDIT211	735
#define IDC_CEDIT220	736
#define IDC_CEDIT221	737
#define IDC_CEDIT300	738
#define IDC_CEDIT301	739
#define IDC_CEDIT310	740
#define IDC_CEDIT311	741
#define IDC_CEDIT320	742
#define IDC_CEDIT321	743
#define IDC_CEDIT400	744
#define IDC_CEDIT401	745
#define IDC_CEDIT410	746
#define IDC_CEDIT411	747
#define IDC_CEDIT420	748
#define IDC_CEDIT421	749
#define IDC_CEDIT500	750
#define IDC_CEDIT501	751
#define IDC_CEDIT510	752
#define IDC_CEDIT511	753
#define IDC_CEDIT520	754
#define IDC_CEDIT521	755

//----- image parameters -----
#define IDD_IDLG	800
#define IDC_IGB1	801
#define IDC_IGB2	802
#define IDC_IGB3	803
#define IDC_IGB4	804
#define IDC_IGB5	805
#define IDC_IGB6	806
#define IDC_IGB7	807
#define IDC_IGB8	808
#define IDC_IGB9	809
#define IDC_IRB1	810
#define IDC_IRB2	811
#define IDC_IRB3	812
#define IDC_IRB4	813
#define IDC_IRB5	814
#define IDC_IRB6	815
#define IDC_IRB7	816
#define IDC_IEDIT1	817
#define IDC_IRB8	818
#define IDC_IRB9	819
#define IDC_IRB10	820
#define IDC_IRB11	821
#define IDC_IRB12	822
#define IDC_IRB13	823
#define IDC_IRB14	824
#define IDC_IEDIT2	825
#define IDC_IRB15	826
#define IDC_IRB16	827
#define IDC_IRB17	828
#define IDC_IRB18	829
#define IDC_IRB19	830
#define IDC_IRB20	831
#define IDC_IRB21	832
#define IDC_IEDIT3	833
#define IDC_IRB22	834
#define IDC_IRB23	835
#define IDC_IRB24	836
#define IDC_IRB25	837
#define IDC_IRB26	838
#define IDC_IRB27	839
#define IDC_IRB28	840
#define IDC_IEDIT4	841
#define IDC_IRB29	842
#define IDC_IRB30	843
#define IDC_IRB31	844
#define IDC_IRB32	845
#define IDC_IRB33	846
#define IDC_IRB34	847
#define IDC_IRB35	848
#define IDC_IEDIT5	849
#define IDC_IRB36	850
#define IDC_IRB37	851
#define IDC_IRB38	852
#define IDC_IRB39	853
#define IDC_IRB40	854
#define IDC_IRB41	855
#define IDC_IRB42	856
#define IDC_IEDIT6	857
#define IDC_IRB43	860
#define IDC_IRB44	861
#define IDC_IRB45	862
#define IDC_IRB46	863
#define IDC_IRB47	864
#define IDC_IRB48	865
#define IDC_IEDIT7	870
#define IDC_IEDIT8	871
#define IDC_IEDIT9	872
#define IDC_IRB49	880
#define IDC_IRB50	881
#define IDC_IRB51	882
#define IDC_RANDOM 883

//----- color parameters -----
#define IDD_FDLG	900
#define IDC_FGB1	910
#define IDC_FGB2	920
#define IDC_FGB3  930
#define IDC_FGB4  940
#define IDC_FTB1	950
#define IDC_FTB2	960
#define IDC_FEDIT1	971
#define IDC_FEDIT2	972
#define IDC_FEDIT3	973
#define IDC_FEDIT4	974
#define IDC_FEDIT5	975
#define IDC_FEDIT6	976

